package com.heiye.comment.biz.consumer;

import cn.hutool.core.util.RandomUtil;
import com.google.common.util.concurrent.RateLimiter;
import com.heiye.comment.biz.constant.MQConstants;
import com.heiye.comment.biz.constant.RedisKeyConstants;
import com.heiye.comment.biz.domain.dataobject.CommentDO;
import com.heiye.comment.biz.domain.mapper.CommentDOMapper;
import com.heiye.comment.biz.model.dto.DeleteCommentCacheMQDTO;
import com.heiye.framework.common.util.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.checkerframework.checker.units.qual.K;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author: heiye
 * @date: 2025/08/04 下午9:14
 * @version: v1.0.0
 * @description: 删除评论缓存
 */
@Slf4j
@Component
@RocketMQMessageListener(
        consumerGroup = "interact_group_" + MQConstants.TOPIC_DELETE_COMMENT_CACHE,
        topic = MQConstants.TOPIC_DELETE_COMMENT_CACHE
)
public class DeleteCommentCacheConsumer implements RocketMQListener<String> {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private CommentDOMapper commentDOMapper;

    // 每秒创建 1000 个令牌
    private RateLimiter rateLimiter = RateLimiter.create(1000);

    @Override
    public void onMessage(String body) {
        rateLimiter.acquire();

        log.info("## 【删除评论缓存】消费者消费成功, body: {}", body);

        // 解析消息转换 DTO
        DeleteCommentCacheMQDTO deleteCommentCacheMQDTO = JsonUtils.parseObject(body, DeleteCommentCacheMQDTO.class);

        if (Objects.nonNull(deleteCommentCacheMQDTO)) {
            // 问题 ID
            Long quizId = deleteCommentCacheMQDTO.getQuizId();
            // 评论 IDS
            List<Long> commentIds = deleteCommentCacheMQDTO.getCommentIds();
            // 构建 Redis Key
            String commentListRedisKey = RedisKeyConstants.buildCommentListKey(quizId);

            // 获取最佳评论 ID
            Long bestCommentId = getBestCommentIdRedis(quizId);

            // 重新同步最新的评论列表
            List<CommentDO> commentDOS = commentDOMapper.selectTop50Comments(quizId, bestCommentId);

            // 使用 Redis Pipeline 批量删除
            redisTemplate.executePipelined(new SessionCallback<>() {
                @Override
                public Object execute(RedisOperations operations) {
                    // 删除评论列表
                    operations.opsForZSet().remove(commentListRedisKey);

                    // 删除评论详情
                    for (Long commentId : commentIds) {
                        operations.delete(RedisKeyConstants.buildCommentDetailKey(commentId));
                    }

                    // 重新构建评论列表
                    for (CommentDO commentDO : commentDOS) {
                        operations.opsForZSet().add(commentListRedisKey,
                                commentDO.getId(),
                                commentDO.getId());
                    }

                    // 随机设置过期时间 5 小时以内
                    int randomExpiryTime = RandomUtil.randomInt(5 * 60 * 60);

                    operations.expire(commentListRedisKey, randomExpiryTime, TimeUnit.SECONDS);
                    return null;
                }
            });
        }
    }

    /**
     * 获取最佳评论并同步到 Redis 缓存
     *
     * @param quizId
     * @return
     */
    private Long getBestCommentIdRedis(Long quizId) {
        // 先判断该问题是否存在最佳评论
        // 先查询 redis
        String commentBestRedisKey = RedisKeyConstants.buildCommentBestKey(quizId);

        boolean hasKey = redisTemplate.hasKey(commentBestRedisKey);
        // 若存在，则从 Redis 中获取出最佳评论 ID
        Long bestCommentId = null;
        if (hasKey) {
            // 获取 Redis 中存储的 value
            String redisValue = (String) redisTemplate.opsForValue().get(commentBestRedisKey);

            if (Objects.nonNull(redisValue)) {
                bestCommentId = Long.parseLong(redisValue);
            }
        }
        // Redis 不存在该数据，则从数据库中获取
        CommentDO bestCommentDO = commentDOMapper.selectBestCommentByQuizId(quizId);
        // 若数据库中存在该数据，则设置 bestCommentId 并，同步到redis中
        if (Objects.nonNull(bestCommentDO)) {
            bestCommentId = bestCommentDO.getId();
            redisTemplate.opsForValue().set(commentBestRedisKey, bestCommentId);
        }
        return bestCommentId;
    }
}
